package com.tuozixuan;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

@Mojo(name = "search")
public class SearchMojo extends AbstractMojo {

	@Parameter(defaultValue = "${project.basedir}", readonly = true)
	private File basedir;

	@Parameter(defaultValue = "${project.build.directory}", readonly = true)
	private File target;

	@Parameter(property = "includeFileExtensions", defaultValue = "java,yml,xml,properties,html", readonly = true)
	private List<String> includeFileExtensions;

	@Parameter(property = "includeFileNamePatterns", readonly = true)
	private List<String> includeFileNamePatterns;

	@Parameter(property = "excludeLinePatterns", readonly = true)
	private List<String> excludeLinePatterns;

	@Parameter(property = "excludeDirectorys", defaultValue = "target", readonly = true)
	private List<String> excludeDirectorys;

	@Parameter(property = "outputFile", defaultValue = "${project.basedir}/simplified-chinese-search.txt", readonly = true)
	private String outputFile;

	public void execute() throws MojoExecutionException, MojoFailureException {

		long t1 = System.currentTimeMillis();
		PluginConfig pluginConfig = this.buildPluginConfig();
		getLog().info(pluginConfig.toString());
		
		String baseAbsolutePath = basedir.getAbsolutePath();
		getLog().info("basedir: " + baseAbsolutePath);

		IOFileFilter fileFilter = this.buildFileFilter(pluginConfig);
		Collection<File> fileList = FileUtils.listFiles(basedir, fileFilter, TrueFileFilter.INSTANCE);
		List<FileResult> fileResultList = fileList.parallelStream()
				.filter(file -> !isExcludeDirectorys(file, baseAbsolutePath, pluginConfig))
				.map(file -> new FileProcessor(file, pluginConfig, getLog()).execute())
				.filter(Optional::isPresent).map(Optional::get)
				.collect(Collectors.toList());

		try {
			getLog().info("outputFile: " + outputFile);
			FileUtils.writeLines(new File(outputFile), fileResultList, true);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("文件信息寫入失敗", e);
		}
		long t2 = System.currentTimeMillis();
		getLog().info("times:" + (t2-t1) + "ms");
		
	}

	private PluginConfig buildPluginConfig() {
		PluginConfig pluginConfig = new PluginConfig();
		pluginConfig.setIncludeFileNamePatterns(includeFileNamePatterns);
		pluginConfig.setIncludeFileExtensions(includeFileExtensions);
		pluginConfig.setExcludeLinePatterns(excludeLinePatterns);
		pluginConfig.setExcludeDirectorys(excludeDirectorys);
		return pluginConfig;
	}

	private boolean isExcludeDirectorys(File file, String baseAbsolutePath, PluginConfig pluginConfig) {

		String relativeFilePath = StringUtils.removeStart(file.getAbsolutePath(), baseAbsolutePath);
		relativeFilePath = StringUtils.removeStart(relativeFilePath, File.separator);
		for (String excludeDirectory : pluginConfig.getExcludeDirectorys()) {

			excludeDirectory = StringUtils.replace(excludeDirectory, "/", File.separator);
			excludeDirectory = StringUtils.replace(excludeDirectory, "\\", File.separator);
			if (StringUtils.startsWith(relativeFilePath, excludeDirectory)) {
				return true;
			}
		}

		return false;
	}

	private IOFileFilter buildFileFilter(PluginConfig pluginConfig) {
		
		List<IOFileFilter> filterList = new ArrayList<>();
		IOFileFilter filter = null;
		if (CollectionUtils.isNotEmpty(pluginConfig.getIncludeFileExtensions())) {
			filter = new SuffixFileFilter(pluginConfig.getIncludeFileExtensions(), IOCase.INSENSITIVE);
			filterList.add(filter);
		}
		
		if (CollectionUtils.isNotEmpty(pluginConfig.getIncludeFileNamePatterns())) {
			List<IOFileFilter> patternfilterList = pluginConfig.getIncludeFileNamePatterns().stream()
					.map(pattern -> new RegexFileFilter(pattern))
					.collect(Collectors.toList());
			filterList.addAll(patternfilterList);
		}
		return new AndFileFilter(filterList);
	}

}
